/* * Copyright (c) 2016 Jesper Öqvist <jesper@llbit.se> * * This file is part of Chunky. * * Chunky is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Chunky is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with Chunky. If not, see <http://www.gnu.org/licenses/>. */ package se.llbit.chunky.ui; import javafx.beans.property.ReadOnlyIntegerWrapper; import javafx.beans.property.ReadOnlyStringWrapper; import javafx.collections.FXCollections; import javafx.fxml.FXML; import javafx.fxml.Initializable; import javafx.scene.control.Alert; import javafx.scene.control.Button; import javafx.scene.control.ButtonType; import javafx.scene.control.TableColumn; import javafx.scene.control.TableRow; import javafx.scene.control.TableView; import javafx.scene.control.Tooltip; import javafx.stage.FileChooser; import javafx.stage.Stage; import se.llbit.chunky.main.SceneHelper; import se.llbit.chunky.renderer.scene.Scene; import se.llbit.json.JsonObject; import se.llbit.json.JsonParser; import se.llbit.log.Log; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.net.URL; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.ResourceBundle; public class SceneChooserController implements Initializable { @FXML private TableView<JsonObject> sceneTbl; @FXML private TableColumn<JsonObject, String> nameCol; @FXML private TableColumn<JsonObject, Number> chunkCountCol; @FXML private TableColumn<JsonObject, String> sizeCol; @FXML private TableColumn<JsonObject, Number> sppCol; @FXML private TableColumn<JsonObject, String> renderTimeCol; @FXML private Button loadSceneBtn; @FXML private Button cancelBtn; @FXML private Button exportBtn; @FXML private Button deleteBtn; private Stage stage; private ChunkyFxController controller; @Override public void initialize(URL location, ResourceBundle resources) { exportBtn.setTooltip(new Tooltip("Exports the selected scene as a Zip archive.")); exportBtn.setOnAction(e -> { if (!sceneTbl.getSelectionModel().isEmpty()) { JsonObject scene = sceneTbl.getSelectionModel().getSelectedItem(); String sceneName = scene.get("fileName").stringValue(""); if (sceneName.isEmpty()) { Log.error("Can not export scene with unknown filename."); return; } FileChooser fileChooser = new FileChooser(); fileChooser.setTitle("Export Scene"); fileChooser .setSelectedExtensionFilter(new FileChooser.ExtensionFilter("Zip files", "*.zip")); fileChooser.setInitialFileName(String.format("%s.zip", sceneName)); File targetFile = fileChooser.showSaveDialog(stage); if (targetFile != null) { Scene.exportToZip(sceneName, targetFile); } } }); deleteBtn.setOnAction(e -> { if (!sceneTbl.getSelectionModel().isEmpty()) { JsonObject scene = sceneTbl.getSelectionModel().getSelectedItem(); String sceneName = scene.get("fileName").stringValue(""); if (sceneName.isEmpty()) { Log.error("Can not delete scene with unknown filename."); return; } Alert alert = new Alert(Alert.AlertType.CONFIRMATION); alert.setTitle("Delete Scene"); alert.setContentText(String.format("Are you sure you want to delete the scene %s? " + "All files for the scene, except snapshot images, will be deleted.", sceneName)); if (alert.showAndWait().get() == ButtonType.OK) { Scene.delete(sceneName, controller.getChunky().options.sceneDir); sceneTbl.getItems().remove(sceneTbl.getSelectionModel().getSelectedItem()); } } }); nameCol.setCellValueFactory(data -> { JsonObject scene = data.getValue(); String sceneName = scene.get("fileName").stringValue(""); return new ReadOnlyStringWrapper(sceneName); }); chunkCountCol.setCellValueFactory(data -> { JsonObject scene = data.getValue(); return new ReadOnlyIntegerWrapper(scene.get("chunkList").array().size()); }); sizeCol.setCellValueFactory(data -> { JsonObject scene = data.getValue(); return new ReadOnlyStringWrapper(String.format("%sx%s", scene.get("width").intValue(400), scene.get("height").intValue(400))); }); sppCol.setCellValueFactory(data -> { JsonObject scene = data.getValue(); return new ReadOnlyIntegerWrapper(scene.get("spp").intValue(0)); }); renderTimeCol.setCellValueFactory(data -> { JsonObject scene = data.getValue(); long renderTime = scene.get("renderTime").longValue(0); int seconds = (int) ((renderTime / 1000) % 60); int minutes = (int) ((renderTime / 60000) % 60); int hours = (int) (renderTime / 3600000); return new ReadOnlyStringWrapper(String.format("%d:%d:%d", hours, minutes, seconds)); }); } public void setStage(Stage stage) { this.stage = stage; sceneTbl.setRowFactory(tbl -> { TableRow<JsonObject> row = new TableRow<>(); row.setOnMouseClicked(e -> { if (e.getClickCount() == 2 && !row.isEmpty()) { JsonObject scene = row.getItem(); String sceneName = scene.get("fileName").stringValue(""); if (sceneName.isEmpty()) { Log.error("Can't load scene with unknown filename."); } else { controller.loadScene(sceneName); e.consume(); stage.close(); } } }); return row; }); loadSceneBtn.setOnAction(e -> { if (!sceneTbl.getSelectionModel().isEmpty()) { JsonObject scene = sceneTbl.getSelectionModel().getSelectedItem(); String sceneName = scene.get("fileName").stringValue(""); if (sceneName.isEmpty()) { Log.error("Can't load scene with unknown filename."); } else { controller.loadScene(sceneName); stage.close(); } } }); cancelBtn.setOnAction(e -> stage.hide()); } private void populateSceneTable(File sceneDir) { List<JsonObject> scenes = new ArrayList<>(); List<File> fileList = SceneHelper.getAvailableSceneFiles(sceneDir); Collections.sort(fileList); for (File sceneFile : fileList) { String fileName = sceneFile.getName(); try { JsonParser parser = new JsonParser(new FileInputStream(new File(sceneDir, fileName))); JsonObject scene = parser.parse().object(); // The scene name and filename may not always match. This can happen // if the user has copied and renamed some scene file. // Therefore we make sure to distinguish scenes by filename. scene.add("fileName", fileName.substring(0, fileName.length() - Scene.EXTENSION.length())); scenes.add(scene); } catch (IOException | JsonParser.SyntaxError e) { Log.warnf("Warning: could not load scene description: %s", fileName); } } sceneTbl.setItems(FXCollections.observableArrayList(scenes)); if (!scenes.isEmpty()) { sceneTbl.getSelectionModel().select(0); } } public void setController(ChunkyFxController controller) { this.controller = controller; populateSceneTable(controller.getChunky().options.sceneDir); } }